/**
 * Copyright 厦门中软海晟信息技术有限公司 版权所有 违者必究 2019
 */
package com.opencvjava.lessons.core;

import com.google.common.collect.Lists;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.List;

import static com.opencvjava.support.util.CvUtils.imshow;
import static com.opencvjava.support.util.CvUtils.mat;
import static org.opencv.imgproc.Imgproc.*;
import static org.opencv.imgcodecs.Imgcodecs.*;
import static org.opencv.core.Core.*;

/**
 * @author : sunzb(sunzb@hsit.com.cn)
 * @date: 2019/1/4
 */
@Service
public class L8_DiscreteFourierTransform {
    private final Logger logger = LoggerFactory.getLogger(L8_DiscreteFourierTransform.class);
    public void test() {
        Mat src1 = mat("wai.jpg", IMREAD_GRAYSCALE);
        Mat src2 = mat("wai2.jpg", IMREAD_GRAYSCALE);
        Mat src3 = mat("wai3.jpg", IMREAD_GRAYSCALE);
        if (src1.empty() || src2.empty() || src3.empty()) {
            throw new RuntimeException("读取图片失败");
        }
        dftTest(src1);
        dftTest(src2);
        dftTest(src3);
    }

    public void dftTest(Mat src) {
        Mat padded = new Mat();                     //expand input image to optimal size
        int rows = src.rows();
        int cols = src.cols();
        int m = getOptimalDFTSize(rows);
        int n = getOptimalDFTSize(cols); // on the border add zero values
        logger.warn("rows:{},cols:{},m:{},n:{}", rows, cols, m, n);
        copyMakeBorder(src, padded, 0, m - src.rows(),
                0, n - src.cols(), BORDER_CONSTANT, Scalar.all(0));
        List<Mat> planes = Lists.newArrayList();
        padded.convertTo(padded, CvType.CV_32F);
        planes.add(padded);
        planes.add(Mat.zeros(padded.size(), CvType.CV_32F));
        Mat complexI = new Mat();
        merge(planes, complexI);         // Add to the expanded another plane with zeros
        // dct(Mat src, Mat dst); 离散余弦变换，是dft的实数部分，不需要定义planes来同时接收实数和虚数部分
        dft(complexI, complexI);         // this way the result may fit in the source matrix
        split(complexI, planes);                               // planes.get(0) = Re(DFT(I)
        // planes.get(0) = Re(DFT(src)) planes.get(1) = Im(DFT(src))
        // compute the magnitude and switch to logarithmic scale
        // magnitude = sqrt(Re(DFT(src))^2 + Im(DFT(src))^2)
        magnitude(planes.get(0), planes.get(1), planes.get(0));// planes.get(0) = magnitude
        Mat magI = planes.get(0);
        Mat matOfOnes = Mat.ones(magI.size(), magI.type());
        add(matOfOnes, magI, magI);         // switch to logarithmic scale
        // switch to logarithmic scale
        // => log(1 + magnitude)
        log(magI, magI);
        // crop the spectrum, if it has an odd number of rows or columns
        magI = magI.submat(new Rect(0, 0, magI.cols() & -2, magI.rows() & -2));
        logger.warn("magI.cols():{}, magI.cols() & -2:{}", magI.cols(), magI.cols() & -2);
        // rearrange the quadrants of Fourier image  so that the origin is at the image center
        int cx = magI.cols() / 2;
        int cy = magI.rows() / 2;
        Mat q0 = new Mat(magI, new Rect(0, 0, cx, cy));   // Top-Left - Create a ROI per quadrant
        Mat q1 = new Mat(magI, new Rect(cx, 0, cx, cy));  // Top-Right
        Mat q2 = new Mat(magI, new Rect(0, cy, cx, cy));  // Bottom-Left
        Mat q3 = new Mat(magI, new Rect(cx, cy, cx, cy)); // Bottom-Right
        Mat tmp = new Mat();               // swap quadrants (Top-Left with Bottom-Right)
        q0.copyTo(tmp);
        q3.copyTo(q0);
        tmp.copyTo(q3);
        q1.copyTo(tmp);                    // swap quadrant (Top-Right with Bottom-Left)
        q2.copyTo(q1);
        tmp.copyTo(q2);
        magI.convertTo(magI, CvType.CV_8UC1);
        normalize(magI, magI, 0, 255, NORM_MINMAX, CvType.CV_8UC1); // Transform the matrix with float values
        // into a viewable image form (float between
        // values 0 and 255).
        imshow("Input Image", src);    // Show the result
        imshow("Spectrum Magnitude", magI);

    }
}
